root@K1:~# cat cc.py 
import time
import json
import requests
import paho.mqtt.publish as publish
import os

# --------------------------
# 1. 软件SPI与ADC驱动
# --------------------------
class SoftSPI:
    def __init__(self, clock_pin, mosi_pin, miso_pin, cs_pin):
        self.clock = clock_pin
        self.mosi = mosi_pin
        self.miso = miso_pin
        self.cs = cs_pin
        
        # 导出GPIO引脚
        for pin in [clock_pin, mosi_pin, miso_pin, cs_pin]:
            if not os.path.exists(f"/sys/class/gpio/gpio{pin}"):
                with open("/sys/class/gpio/export", "w") as f:
                    f.write(str(pin))
        
        # 配置引脚方向
        with open(f"/sys/class/gpio/gpio{clock_pin}/direction", "w") as f:
            f.write("out")
        with open(f"/sys/class/gpio/gpio{mosi_pin}/direction", "w") as f:
            f.write("out")
        with open(f"/sys/class/gpio/gpio{miso_pin}/direction", "w") as f:
            f.write("in")
        with open(f"/sys/class/gpio/gpio{cs_pin}/direction", "w") as f:
            f.write("out")
        
        # 初始状态
        self.write_pin(cs_pin, 1)
        self.write_pin(clock_pin, 0)
    
    def write_pin(self, pin, value):
        with open(f"/sys/class/gpio/gpio{pin}/value", "w") as f:
            f.write("1" if value else "0")
    
    def read_pin(self, pin):
        with open(f"/sys/class/gpio/gpio{pin}/value", "r") as f:
            return f.read().strip() == "1"
    
    def transfer(self, data):
        response = bytearray()
        for byte in data:
            response_byte = 0
            for bit in range(7, -1, -1):
                self.write_pin(self.mosi, (byte >> bit) & 1)
                self.write_pin(self.clock, 1)
                time.sleep(0.0001)
                response_byte |= self.read_pin(self.miso) << bit
                self.write_pin(self.clock, 0)
                time.sleep(0.0001)
            response.append(response_byte)
        return response

class MCP3008ADC:
    def __init__(self, spi, channel=0):
        self.spi = spi
        self.channel = channel
    
    def read(self):
        command = [1, (8 + self.channel) << 4, 0]
        self.spi.write_pin(self.spi.cs, 0)
        time.sleep(0.0001)
        response = self.spi.transfer(command)
        self.spi.write_pin(self.spi.cs, 1)
        adc_value = ((response[1] & 3) << 8) | response[2]
        return adc_value

# --------------------------
# 2. 硬件配置
# --------------------------
SPI_CLOCK = 70
SPI_MISO = 71
SPI_MOSI = 72
SPI_CS = 73
RELAY_PIN = 74

spi = SoftSPI(SPI_CLOCK, SPI_MOSI, SPI_MISO, SPI_CS)
adc = MCP3008ADC(spi, channel=0)

# --------------------------
# 3. 边端AI分析
# --------------------------
def edge_ai_analyze(soil_data):
    url = "http://localhost:11434/v1/chat/completions"
    prompt = f"""
    土壤湿度状态：{soil_data['status']}（值：{soil_data['value']}）
    时间：{soil_data['record_time']}
    请判断是否需要浇水，理由简洁（不超过10字）
    """
    try:
        response = requests.post(
            url,
            json={
                "model": "qwen2.5:0.5b",
                "messages": [{"role": "user", "content": prompt}]
            },
            timeout=15
        )
        return response.json()["choices"][0]["message"]["content"]
    except Exception as e:
        return f"分析失败：{str(e)}"

# --------------------------
# 4. 硬件控制
# --------------------------
def control_irrigation(decision):
    # 初始化继电器引脚
    if not os.path.exists(f"/sys/class/gpio/gpio{RELAY_PIN}"):
        with open("/sys/class/gpio/export", "w") as f:
            f.write(str(RELAY_PIN))
        with open(f"/sys/class/gpio/gpio{RELAY_PIN}/direction", "w") as f:
            f.write("out")
    
    # 根据决策控制继电器
    if "需要浇水" in decision:
        with open(f"/sys/class/gpio/gpio{RELAY_PIN}/value", "w") as f:
            f.write("1")
        return "已启动浇水"
    else:
        with open(f"/sys/class/gpio/gpio{RELAY_PIN}/value", "w") as f:
            f.write("0")
        return "已停止浇水"

# --------------------------
# 5. MQTT发送
# --------------------------
EMQX_HOST = "192.168.0.100"
EMQX_PORT = 1883
MQTT_TOPIC = "sensor/1"

def send_mqtt_message(soil_data, ai_decision):
    # MQTT消息包含所有需入库的字段
    payload = {
        "status": soil_data["status"],
        "value": soil_data["value"],
        "record_time": soil_data["record_time"],
        "ai_decision": ai_decision  # AI决策
    }
    try:
        publish.single(
            topic=MQTT_TOPIC,
            payload=json.dumps(payload),
            hostname=EMQX_HOST,
            port=EMQX_PORT,
            client_id="MusePi_SoilSensor_AI"
        )
        return f"MQTT发送成功：{payload}"
    except Exception as e:
        return f"MQTT发送失败：{str(e)}"

# --------------------------
# 6. 数据采集
# --------------------------
def get_soil_status():
    adc_value = adc.read()
    normalized_value = adc_value / 1023.0
    status = "湿" if normalized_value < 0.5 else "干"
    return {
        "status": status,
        "value": round(normalized_value, 3),
        "record_time": time.strftime("%Y-%m-%d %H:%M:%S")
    }

# --------------------------
# 7. 主程序
# --------------------------
if __name__ == "__main__":
    try:
        print("土壤湿度AI控制系统启动（按Ctrl+C停止）")
        while True:
            soil_data = get_soil_status()
            print(f"采集数据：{soil_data}")
            
            ai_decision = edge_ai_analyze(soil_data)
            print(f"AI决策：{ai_decision}")
            
            control_result = control_irrigation(ai_decision)
            print(f"设备控制：{control_result}")
            
            mqtt_result = send_mqtt_message(soil_data, ai_decision)
            print(f"云端同步：{mqtt_result}\n")
            
            time.sleep(30)
    except KeyboardInterrupt:
        print("\n程序已停止")
    finally:
        # 清理GPIO
        for pin in [SPI_CLOCK, SPI_MOSI, SPI_MISO, SPI_CS, RELAY_PIN]:
            if os.path.exists(f"/sys/class/gpio/gpio{pin}"):
                with open("/sys/class/gpio/unexport", "w") as f:
                    f.write(str(pin))